Step FunctionsからLambda関数を実行する書き方2つの違い
Step FunctionsからLambda関数を実行したい場合、ASL(Amazon State Languageの略。ステートマシンの実装をこの形式で書く)の書き方が2つあります。この違いを調べました。
方法1: Resourceに関数のARNを直接書く
{ "StartAt":"CallLambda", "States":{ "CallLambda":{ "Type":"Task", "Resource":"arn:aws:lambda:ap-northeast-1:123456789012:function:MyFunction", "End":true } } }
方法2: Parameters.FunctionNameに関数名を書く。Resourceは arn:aws:states:::lambda:invoke
固定
{ "StartAt":"CallLambda", "States":{ "CallLambda":{ "Type":"Task", "Resource":"arn:aws:states:::lambda:invoke", "Parameters":{ "FunctionName":"MyFunction" }, "End":true } } }
FunctionName
の値は、関数のARNでも可能です。
{ "StartAt":"CallLambda", "States":{ "CallLambda":{ "Type":"Task", "Resource":"arn:aws:states:::lambda:invoke", "Parameters":{ "FunctionName":"arn:aws:lambda:ap-northeast-1:123456789012:function:MyFunction" }, "End":true } } }
以下、この2つの書き方によって生じる違いを4つご紹介します。
違い1: コールバックタスクが書ける/書けない
コールバックタスクとは、ステートマシン実行を一時中断できる機能です。例えば外部システムをワークフローの途中で呼び出す必要があったとして、外部システムでの処理完了までステートマシン実行を一時中断し、完了したら再開する、というようなことが実現できます。他にも、人による承認ステップをステートマシン内に組み込みたい場合などにも役立ちます。
Lambda関数実行でコールバックタスクを作成する場合、Resource
フィールド末尾に.waitForTaskToken
の指定が必要で、この書き方が許されているのは方法2のようにarn:aws:states:::lambda:invoke
と書いている場合のみです。(つまりarn:aws:states:::lambda:invoke.waitForTaskToken
となります)
違い2: handlerメソッドのevent引数値の渡し方が異なる
「方法1: Resourceに関数のARNを直接書く」の場合、Parameters
フィールドに書いた値がそのままLambda関数handlerメソッドのeventオブジェクトに格納されます。
{ "StartAt":"CallLambda", "States":{ "CallLambda":{ "Type":"Task", "Resource":"arn:aws:lambda:ap-northeast-1:123456789012:function:MyFunction", "Parameters": { "hoge": "hoge val" }, "End":true } } }
exports.handler = (event, _context, callback) => { console.log(event); // { hoge: 'hoge val' } callback(null, { "ret": "ret val" }); };
一方、方法2の場合は階層が一つ深くなります。Parameters.Payload
以下に書きます。
{ "StartAt":"CallLambda", "States":{ "CallLambda":{ "Type":"Task", "Resource":"arn:aws:states:::lambda:invoke", "Parameters":{ "FunctionName":"MyFunction", "Payload": { "hoge": "hoge val" }, }, "End":true } } }
違い3: Stateの出力が変わる
「方法1: Resourceに関数のARNを直接書く」の場合、Stateの出力は関数の返り値と同じになります。
一方、方法2の場合は、関数の返り値はState出力のJSONのPayload
キー以下に格納されます。他のキーにはメタデータが格納されます。
{ "ExecutedVersion": "$LATEST", "Payload": { "ret": "ret val" }, "SdkHttpMetadata": { "AllHttpHeaders": { "X-Amz-Executed-Version": [ "$LATEST" ], "x-amzn-Remapped-Content-Length": [ "0" ], "Connection": [ "keep-alive" ], "x-amzn-RequestId": [ "91a1f8c6-47c5-4f79-8a62-d2ae2c61cfe2" ], "Content-Length": [ "17" ], "Date": [ "Wed, 30 Jun 2021 09:03:53 GMT" ], "X-Amzn-Trace-Id": [ "root=1-60dc3378-1f4e87c55ff9020c76c3bd63;sampled=0" ], "Content-Type": [ "application/json" ] }, "HttpHeaders": { "Connection": "keep-alive", "Content-Length": "17", "Content-Type": "application/json", "Date": "Wed, 30 Jun 2021 09:03:53 GMT", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", "x-amzn-RequestId": "91a1f8c6-47c5-4f79-8a62-d2ae2c61cfe2", "X-Amzn-Trace-Id": "root=1-60dc3378-1f4e87c55ff9020c76c3bd63;sampled=0" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { "RequestId": "91a1f8c6-47c5-4f79-8a62-d2ae2c61cfe2" }, "StatusCode": 200 }
違い4: 関数実行方法が限定される/されない
方法2では、Parametersフィールド以下に以下の3パラメーターを指定することによって、より色々な関数実行方法が実現できます。(だからEventオブジェクトに値を渡す時はPayload
に一つ階層下げないといけないんですね)
方法1では使えません。
ClientContext
すみませんよくわかっていませんが、モバイルアプリでクライアントアプリケーションによってLambdaに送信されたクライアントコンテキストの情報を格納するパラメーターだそうです。
Lambdaのhandlerメソッドの第2引数context
のclientContext
プロパティで値が確認できます。
InvocationType
Lambda関数の呼び出し方の指定。デフォルトはRequestResponse
で、同期呼び出し、つまり関数が結果を返すまでStepFunctionsは待ちます。Event
にすると非同期呼び出しになり結果を待ちません。(DryRun
- Validate parameter values and verify that the user or role has permission to invoke the function. というのもあります)
Qualifier
関数のバージョンやエイリアスを指定するためのパラメーター。ですがこのパラメーターが使えなくても、関数のARNや名前を書く際の末尾に:(バージョン番号 or エイリアス名)
と入れれば任意のバージョンやエイリアスを指定できるので特に困らないかなと思います。
蛇足: CDKでの書き分け方
Lambda関数のStepFunctionsからの実行をCDKで書く場合、@aws-cdk/aws-stepfunctions-tasksのLambdaInvoke constructを利用できます。こちらを使う場合、Construct PropsのpayloadResponseOnly
値をtrue
にすると「方法1: Resourceに関数のARNを直接書く」の書き方になり、false(デフォルト)にすると方法2になります。
まとめ
Step FunctionsからLambda関数を実行する書き方2つと、その違いをご紹介しました。
基本的に「方法1: Resourceに関数のARNを直接書く」を使うほうがシンプルで良いかと思います。上に挙げた諸々の「方法1だと実現できない部分」が必要な場合のみ、方法2を使いましょう。